package ji

import (
	"net/http"
	"strings"
)

type Router struct {
	roots    map[string]*node
	handlers map[string]HandlerFunc
}

func newRouter() *Router {
	return &Router{
		roots:    make(map[string]*node),
		handlers: make(map[string]HandlerFunc),
	}
}

// 拆解path
func parsePath(path string) []string {
	vs := strings.Split(path, "/")

	parts := make([]string, 0)
	for _, v := range vs {
		if v != "" {
			parts = append(parts, v)
			if v[0] == '*' { // !
				break
			}
		}
	}
	return parts
}

// 添加路由
// method 请求方式
// path 完整路径
// handlerFunc 处理函数
func (r *Router) addRoute(method string, path string, handlerFunc HandlerFunc) {
	parts := parsePath(path)

	key := method + "-" + path
	if _, ok := r.roots[method]; !ok {
		r.roots[method] = &node{}
	}
	r.roots[method].insert(path, parts, 0)
	r.handlers[key] = handlerFunc
}

// 查询
// method 请求方式
// path 完整路径
func (r *Router) getRoute(method string, path string) (*node, map[string]string) {
	searchParts := parsePath(path)
	params := make(map[string]string)

	root, ok := r.roots[method]
	if !ok {
		return nil, nil
	}

	n := root.search(searchParts, 0)
	if n != nil {
		parts := parsePath(n.path)
		for index, part := range parts {
			// ddy/:xxx 	实际:ddy/oa
			if part[0] == ':' {
				//params["xxx"] = "oa"
				params[part[1:]] = searchParts[index]
			}
			// eeh/*filepath/doc 实际:ddh/manman/printf
			if part[0] == '*' && len(part) > 1 {
				// params["filepath/doc"] = "manman/printf"
				params[part[1:]] = strings.Join(searchParts[index:], "/")
				break
			}
		}
		return n, params
	}
	return nil, nil
}

func (r *Router) handle(c *Context) { //处理器收集并执行
	n, params := r.getRoute(c.GetMethod(), c.GetPath())
	if n != nil { //todo bug!![trie中insert没写好]
		c.Params = params
		key := c.GetMethod() + "-" + n.path
		//r.handlers[key](c)
		c.middlewares = append(c.middlewares, r.handlers[key])
	} else {
		c.middlewares = append(c.middlewares, func(ctx *Context) {
			c.String(http.StatusNotFound, "404 NOT FOUND %s\n", c.GetPath())
		})
	}
	c.Next() // 用于执行所有处理函数
}

func (r *Router) AddRoute(method string, path string, handlerFunc HandlerFunc) {
	r.addRoute(method, path, handlerFunc)
}

func (r *Router) Handle(c *Context) {
	r.handle(c)
}
